﻿using CsvHelper.Configuration;
using CsvHelper;
using System.Globalization;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Xml.Linq;
using DataWorks_Tools.MatlabDetails;

namespace DataWorks_Tools.BasicMethods
{
    public static class ReadfromCSV
    {
        /// <summary>
        /// 读取单个csv生成的结构体
        /// </summary>
        public struct CSVImport
        {
            public byte status;//标识数据导入的状态参数，如为0则正常，为1有空行或nan，为2则是csv文件不是数字，为3则文件被占用
            public List<List<double>> lists;//所有列的数据
            public double[][] array;//所有列的数据
            public string[] headers;//标题行
            public string[] originalheaders;//标题行
            public int columncount;//列数
            public string name;//文件名
            public string datetime;//时间精确到日期
            public string subdirectory;//文件夹名称
            public string datetimesecond;//时间精确到半小时
            public bool Iscontinue;//判断计算程序是否继续
            public string errorname;//错误列名
            public int errorrow;//错误行数
        }
        /// <summary>
        /// 从csv文件读取所有列的数据的基本方法(输入和输出的都在一起），如有日期字符串数据会识别为0
        /// </summary>
        /// <param name="file"></param>
        /// <returns>csv数据结构体</returns>
        public static async Task<CSVImport> GetDatafromCSVAsync(this FileInfo file)
        {
            var basestruct = new CSVImport()
            {
                status = 0,
                name = file.Name.Split('.')[0],
                Iscontinue = true,
                errorname = "no",
                errorrow = -1,
            };
            await Task.Run(() =>
            {
                if (!BasicFilesOperation.YXHFileIsZero(file.FullName))
                {
                    string[] filestring = file.Name.Split('-');
                    basestruct.datetime = filestring[0].Replace("_", "-");
                    basestruct.subdirectory = filestring[0].Substring(5);//"2024_01_23"取原始字符串从索引5开始到末尾的子字符串，即"01_23"
                    basestruct.datetimesecond = DateTimeMethods.YXHDatetoSeconds(basestruct.datetime, filestring[1]);
                    Encoding encoding = Encoding.Default;
                    FileStream fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
                    StreamReader sr = new StreamReader(fs, encoding, false, 8192);
                    string? strLine = "";
                    //记录每行记录中的各字段内容
                    string[]? aryLine = null;
                    int countnum = 2;
                    int columnCount = 0;
                    //标示是否是读取的第一行
                    bool IsFirst = true;
                    List<List<double>> datalist = new List<List<double>>();
                    while ((strLine = sr.ReadLine()) != null)
                    {
                        countnum++;
                        if (IsFirst == true)
                        {
                            //改为小写，去掉下划线，空格和N
                            basestruct.headers = strLine.ReName().Split(',');
                            basestruct.originalheaders= strLine.Split(",");
                            IsFirst = false;
                            columnCount = basestruct.headers.Length;
                            basestruct.columncount = columnCount;
                            for (int i = 0; i < columnCount; i++)
                            {
                                datalist.Add(new List<double>());
                            }
                        }
                        else
                        {
                            aryLine = strLine.Split(',');
                            for (int j = 0; j < columnCount; j++)
                            {

                                var transfersuceess = double.TryParse(aryLine[j], out double value);

                                if (transfersuceess)
                                {
                                    if (!double.IsNaN(value))
                                    {
                                        datalist[j].Add(value);
                                    }
                                    else
                                    {
                                        datalist[j].Add(0);
                                        basestruct.status = 1;//有空行或nan
                                        basestruct.errorname = basestruct.headers!=null? basestruct.headers[j]:"titleerror";
                                        basestruct.errorrow = countnum;
                                        basestruct.Iscontinue = false;
                                        return;
                                    }
                                }
                                else
                                {
                                    // 尝试将字符串解析为 DateTime
                                    bool isDateTime = DateTime.TryParse(aryLine[j], out DateTime dateValue);
                                    if (isDateTime)
                                    {
                                        datalist[j].Add(0);
                                    }
                                    else
                                    {
                                        datalist[j].Add(0);
                                        basestruct.status = 2;//不是数字
                                        basestruct.errorname = basestruct.headers != null ? basestruct.headers[j] : "titleerror";
                                        basestruct.errorrow = countnum;
                                        basestruct.Iscontinue = false;
                                        return;
                                    }
                                }
                            }
                        }
                    }
                    basestruct.lists = datalist;
                    sr.Close();
                    sr.Dispose();
                    fs.Close();
                    fs.Dispose();
                }
                else
                {
                    basestruct.status = 3;//文件被占用
                    basestruct.Iscontinue = false;
                    return;
                }
            });
            return basestruct;
        }

        /// <summary>
        /// 根据指定的通道名来筛选已经读取过的CSVImport的列数据
        /// </summary>
        /// <param name="csvimport"></param>
        /// <param name="channame"></param>
        /// <returns></returns>
        public static async Task<List<double>?> GetSpecifiedColumnDataAsync(this CSVImport csvimport, string channame)
        {
            int index = -1;
            var newname= channame.ReName();
            await Task.Run(() =>
            {
                index = Array.IndexOf(csvimport.headers, newname);
            });
            if (index != -1)
            {
                return csvimport.lists[index];
            }
            else
            {
                return null;
               
            }

        }
        /// <summary>
        /// 根据指定的通道名组来筛选已经读取过的CSVImport的多列的数据
        /// </summary>
        /// <param name="csvimport"></param>
        /// <param name="channames"></param>
        /// <returns></returns>
        public static async Task<List<double[]>> GetSpecifiedMultiColumnDataAsync(this CSVImport csvimport, List<string>? channames)
        {
            List<double[]> output = new List<double[]>();
            await Task.Run(() =>
            {
                foreach (var name in channames)
                {
                    var newname = name.ReName();
                    int index = Array.IndexOf(csvimport.headers, newname);
                    if (index != -1)
                    {
                        output.Add(csvimport.lists[index].ToArray());
                    }
                }
            });
            return output;
        }
        /// <summary>
        /// 根据指定的通道名来筛选已经读取过的CSVImport的列数据委托版
        /// </summary>
        /// <param name="csvimport">csv数据所有列</param>
        /// <param name="func">通道名称的委托方法</param>
        /// <returns></returns>
        /// <exception cref="Exception">通道名称csv找不到的异常</exception>
        public static async Task<List<double>?> GetSpecifiedColumnDataDelAsync(CSVImport csvimport, Func<string> func)
        {
            int index = -1;
            await Task.Run(() =>
            {
                index = Array.IndexOf(csvimport.headers, func());
            });
            if (index != -1)
            {
                return csvimport.lists[index];
            }
            else
            {
                return null;
            }

        }
        /// <summary>
        /// 为第一个csv单列添加0，点数由CausalOrder决定
        /// </summary>
        /// <param name="data"></param>
        /// <param name="CausalOrder">因果阶数</param>
        /// <returns></returns>
        public static async Task AddZerosforFirstCsv1Chan(this List<double> data, int CausalOrder)
        {
            await Task.Run(() =>
            {
                for (int i = 0; i < CausalOrder; i++)
                {
                    data.Insert(0, 0);
                }
            });
        }
        /// <summary>
        /// 为第一个csv多列添加0，点数由CausalOrder决定
        /// </summary>
        /// <param name="data"></param>
        /// <param name="CausalOrder"></param>
        /// <returns></returns>
        public static async Task AddZerosforFirstCsvMultiChans(this List<double[]> data, int CausalOrder)
        {
            await Task.Run(() =>
            {
                for (int i = 0; i < data.Count; i++)
                {
                    double[] zeros = Enumerable.Repeat(0.0, CausalOrder).ToArray();
                    data[i] = zeros.Concat(data[i]).ToArray();
                }
            });
        }

        /// <summary>
        /// 生成一组全部为0的List<double[]>，点数由CausalOrder决定，维数由inputnames文件确定
        /// </summary>
        /// <param name="data"></param>
        /// <param name="CausalOrder"></param>
        /// <returns></returns>
        public static async Task<List<double[]>> AddZeros(List<string>? inputnames, int CausalOrder)
        {
            List<double[]> zeroslst = new List<double[]>();
            await Task.Run(() =>
            {
                for (int i = 0; i < inputnames?.Count; i++)
                {
                    double[] zeros = Enumerable.Repeat(0.0, CausalOrder).ToArray();
                    zeroslst.Add(zeros);
                }
            });
            return zeroslst;
        }
        /// <summary>
        /// 提取一个list的最后CausalOrder数量的单列的数据并返回
        /// </summary>
        /// <param name="data"></param>
        /// <param name="CausalOrder"></param>
        /// <returns></returns>
        public static async Task<List<double>> GetLastCausalOrder1ChanAsync(this List<double> data, int CausalOrder)
        {
            List<double> lastCausalOrder = await Task.Run(() =>
            {
                return data.GetRange(data.Count - CausalOrder, CausalOrder);
            });
            return lastCausalOrder;
        }
        /// <summary>
        ///  提取一个list的最后CausalOrder数量的多列的数据并返回
        /// </summary>
        /// <param name="data"></param>
        /// <param name="CausalOrder"></param>
        /// <returns></returns>
        public static async Task<List<double[]>> GetLastCausalOrderMultiChansAsync(this List<double[]> data, int CausalOrder)
        {
            List<double[]> lastCausalOrder = await Task.Run(() =>
            {
                List<double[]> result = new List<double[]>();
                foreach (var row in data)
                {
                    result.Add(row.Skip(Math.Max(0, row.Length - CausalOrder)).ToArray());
                }
                return result;
            });
            return lastCausalOrder;
        }

        /// <summary>
        /// 把2个List<double[]合并到一起，主要用于把前一个csv的最后50个数据添加到后一个csv的数据中
        /// </summary>
        /// <param name="data1"></param>
        /// <param name="data2"></param>
        /// <returns></returns>
        public static async Task MergeDataAsync(List<double[]> data1, List<double[]> data2)
        {
            if (data1.Count==data2.Count && data1.Count>0)
            {
                await Task.Run(() =>
                {
                    List<double[]> result = new List<double[]>();
                    for (int i = 0; i < data1.Count; i++)
                    {
                        data2[i]=(data1[i].Concat(data2[i]).ToArray());
                    }
                });
            }
        }
        /// <summary>
        /// 把一个List<double[]>转换成2维double数组，后面用于转二维矩阵的异步方法
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static async Task<double[][]> Listto2DArrayAsync(this List<double[]> data)
        {
            return await Task.Run(() =>
            {
                double[][] twodArray = new double[data.Count][];

                for (int i = 0; i < data.Count; i++)
                {
                    twodArray[i] = data[i];
                }
                return twodArray;
            });
        }
        /// <summary>
        /// 把一个List<List<double>>转换成2维double数组，后面用于转二维矩阵异步方法
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static async Task<double[][]> Listto2DArrayAsync(this List<List<double>> data)
        {
            return await Task.Run(() =>
            {
                double[][] twodArray = new double[data.Count][];

                for (int i = 0; i < data.Count; i++)
                {
                    twodArray[i] = data[i].ToArray();
                }
                return twodArray;
            });
        }
        /// <summary>
        /// 把一个List<double[]>转换成2维double数组，后面用于转二维矩阵
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static double[][] Listto2DArray(this List<double[]> data)
        {
            double[][] twodArray = new double[data.Count][];

            for (int i = 0; i < data.Count; i++)
            {
                twodArray[i] = data[i];
            }
            return twodArray;
        }
       
        /// <summary>
        /// 把2维数组转成List<List<double>> 
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static List<List<double>> TwoDArray2List(this double[][] data)
        {
            List<List<double>> convertedLists = new List<List<double>>();

            // 遍历二维数组中的每个内部数组，将其转换为列表，并添加到转换后的列表中
            foreach (double[] array in data)
            {
                List<double> innerList = new List<double>(array);
                convertedLists.Add(innerList);
            }
            return convertedLists;
        }
    }
}